package com.richard.room.operator.processor;

import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;

import com.google.auto.service.AutoService;
import com.richard.room.operator.annotation.Description;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;

@AutoService(Processor.class)
@SupportedOptions("MODULE_NAME")
@SupportedAnnotationTypes({"androidx.room.Entity"})
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class RoomEntityProcessor extends AbstractProcessor {

    /**
     * Property 类
     */
    private final String propertyClass = "com.richard.room.operator.api.Property";

    /**
     * 文件生成器
     */
    private Filer filer;

    /**节点工具类*/
    private Elements elementUtils;


    /**
     * 初始化
     *
     * @param processingEnv 这个参数提供了若干工具类，供编写生成 Java 类时所使用
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filer = processingEnv.getFiler();
    }

    /**
     * 编写生成 Java 类的相关逻辑
     *
     * @param set              支持处理的注解集合
     * @param roundEnvironment 通过该对象查找指定注解下的节点信息
     * @return true: 表示注解已处理，后续注解处理器无需再处理它们；false: 表示注解未处理，可能要求后续注解处理器处理
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        System.out.println("------------------进入处理RoomEntity注解----------------------");
        if (set == null || set.isEmpty()) {
            return false;
        }

        //节点工具类
        elementUtils = processingEnv.getElementUtils();

        //获取当前注解下的节点信息
        Set<? extends Element> rootElements = roundEnvironment.getElementsAnnotatedWith(Entity.class);

        if (rootElements == null || rootElements.isEmpty()) {
            return false;
        }

        //记录实体关系类
        List<EntityRelation> entityRelationList = new ArrayList<>();

        for (Element item : rootElements) {
            //记录复合主键
            List<String> compositePK = new ArrayList<>();
            //记录列名
            List<String> columnNames = new ArrayList<>();

            //构建java类
            ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(
                    ClassName.bestGuess("com.richard.room.operator.api.Entity")
                    , ClassName.bestGuess(item.asType().toString())
            );
            String relationEntityClass = String.format("%s_", item.getSimpleName());
            TypeSpec.Builder builder = TypeSpec.classBuilder(relationEntityClass)
                    .addSuperinterface(parameterizedTypeName)
                    .addModifiers(Modifier.PUBLIC);

            //记录复合主键
            Entity entity = item.getAnnotation(Entity.class);
            if (entity != null && entity.primaryKeys() != null && entity.primaryKeys().length > 0) {
                compositePK.addAll(Arrays.asList(entity.primaryKeys()));
            }

            //生成获取表名的方法
            String tableNameFieldName = this.generateTableNameFiledAndMethod(builder, item);

            //生成获取表描述属性和方法
            this.generateTableDescriptionFiledAndMethod(builder, item);

            //处理数据表实体类下的数据表字段属性
            boolean isGenerateGetIdMethod = false;
            for (Element enclosedElement : item.getEnclosedElements()) {
                if (enclosedElement.getKind() != ElementKind.FIELD
                        || enclosedElement.getAnnotation(Ignore.class) != null) {
                    continue;
                }

                //生成class 类属性
                if (this.generateField(builder, tableNameFieldName, enclosedElement, compositePK)) {
                    isGenerateGetIdMethod = true;
                }
                columnNames.add(enclosedElement.getSimpleName().toString());
            }

            //记录保存实体关系
            entityRelationList.add(new EntityRelation(
                    item.toString()
                    , item.getEnclosingElement().toString().concat(".").concat(relationEntityClass)
            ));

            //生成entity 实例
            this.generateEntityInstanceField(builder, item);

            //生成实体类class属性和获取方法
            this.generateEntityClassAndMethod(builder, item);

            //生成当前Entity的全部属性参数数组
            this.generatePropertyArrayMethod(builder, columnNames);

            //如果没有主键id
            if (!isGenerateGetIdMethod) {
                this.generateIdPropertyMethod(builder, null);
            }

            //生成复合主键属性和获取方法
            this.generateCompositePKMethod(builder, compositePK);

            //生成绑定属性值的方法
            this.generateBindInsertionAdapterValue(builder, item);

            //生成绑定DeleteAdapter属性值的方法
            this.generateBindDeleteAdapterValue(builder, item, compositePK);

            //生成绑定update语句属性值的方法
            this.generateBindUpdateAdapterValue(builder, item, compositePK);

            //输出java 文件
            this.outPutJavaFile(builder.build(), item.getEnclosingElement().toString());
        }

        //生成实体管理类
        this.generateEntityManager(entityRelationList);

        System.out.println("------------------进入处理RoomEntity注解End----------------------");

        return true;
    }

    /**
     * 输出java 文件
     *
     * @param javaClass   java 类
     * @param packageName 包名
     */
    private void outPutJavaFile(TypeSpec javaClass, String packageName) {
        // 指定包路径，构建文件体
        JavaFile javaFile = JavaFile.builder(packageName, javaClass).build();
        try {
            // 创建文件
            javaFile.writeTo(filer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成绑定DeleteAdapter属性值的方法
     *
     * @param builder       TypeSpecBuilder
     * @param entityElement 类节点
     * @param compositePK   复合主键
     */
    private void generateBindDeleteAdapterValue(TypeSpec.Builder builder, Element entityElement, List<String> compositePK) {
        String valueField = "stmtValue";
        String stmtField = "stmt";

        //生成方法
        MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder("bindDeleteAdapterValue")
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Override.class)
                .returns(TypeName.VOID)
                .addParameter(ClassName.bestGuess("androidx.sqlite.SQLiteStatement"), stmtField)
                .addParameter(ClassName.bestGuess(entityElement.asType().toString()), valueField);

        methodSpecBuilder.addStatement("int bindIndex = 1");

        for (Element fieldElement : this.getPKElementList(entityElement, compositePK)) {
            this.handleBindValue(fieldElement, methodSpecBuilder, stmtField, valueField, false, false);
        }

        builder.addMethod(methodSpecBuilder.build());
    }

    /**
     * 生成绑定InsertionAdapter属性值的方法
     *
     * @param builder       TypeSpecBuilder
     * @param entityElement 类节点
     */
    private void generateBindInsertionAdapterValue(TypeSpec.Builder builder, Element entityElement) {
        String valueField = "stmtValue";
        String stmtField = "stmt";

        //生成方法
        MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder("bindInsertionAdapterValue")
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Override.class)
                .returns(TypeName.VOID)
                .addParameter(ClassName.bestGuess("androidx.sqlite.SQLiteStatement"), stmtField)
                .addParameter(ClassName.bestGuess(entityElement.asType().toString()), valueField);

        methodSpecBuilder.addStatement("int bindIndex = 1");

        for (Element fieldElement : entityElement.getEnclosedElements()) {
            if (fieldElement.getKind() != ElementKind.FIELD
                    || fieldElement.getAnnotation(Ignore.class) != null) {
                continue;
            }
            this.handleBindValue(fieldElement, methodSpecBuilder, stmtField, valueField, true, true);
        }

        builder.addMethod(methodSpecBuilder.build());
    }

    /**
     * 生成绑定update语句属性值的方法
     *
     * @param builder       TypeSpecBuilder
     * @param entityElement 类节点
     */
    private void generateBindUpdateAdapterValue(TypeSpec.Builder builder, Element entityElement, List<String> compositePK) {
        String valueField = "stmtValue";
        String stmtField = "stmt";

        //生成方法
        MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder("bindUpdateAdapterValue")
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Override.class)
                .returns(TypeName.VOID)
                .addParameter(ClassName.bestGuess("androidx.sqlite.SQLiteStatement"), stmtField)
                .addParameter(ClassName.bestGuess(entityElement.asType().toString()), valueField);

        methodSpecBuilder.addStatement("int bindIndex = 1");

        for (Element fieldElement : entityElement.getEnclosedElements()) {
            if (fieldElement.getKind() != ElementKind.FIELD
                    || fieldElement.getAnnotation(Ignore.class) != null) {
                continue;
            }
            this.handleBindValue(fieldElement, methodSpecBuilder, stmtField, valueField, true, false);
        }

        methodSpecBuilder.addCode("\n//绑定where条件参数\n");

        //生成绑定where条件参数代码
        for (Element fieldElement : this.getPKElementList(entityElement, compositePK)) {
            this.handleBindValue(fieldElement, methodSpecBuilder, stmtField, valueField, false, false);
        }

        builder.addMethod(methodSpecBuilder.build());
    }

    /**
     * 获取主键属性列表
     *
     * @param entityElement 实体节点
     * @param compositePK   复合主键
     * @return 主键属性列表
     */
    private List<Element> getPKElementList(Element entityElement, List<String> compositePK) {
        //处理where条件参数
        final List<Element> primaryKeyElement = new ArrayList<>();
        for (Element fieldElement : entityElement.getEnclosedElements()) {
            if (fieldElement.getKind() != ElementKind.FIELD
                    || fieldElement.getAnnotation(Ignore.class) != null) {
                continue;
            }

            //是否属于主键Id
            if (fieldElement.getAnnotation(PrimaryKey.class) != null) {
                primaryKeyElement.add(fieldElement);
                break;
            }

            //字段列信息
            String columnName = null;
            ColumnInfo columnInfo = fieldElement.getAnnotation(ColumnInfo.class);
            if (columnInfo != null) {
                columnName = columnInfo.name();
            }

            if (columnName == null) {
                columnName = fieldElement.getSimpleName().toString();
            }

            int index = compositePK.indexOf(columnName);
            if (index >= 0) {
                primaryKeyElement.add(fieldElement);
            }
        }

        return primaryKeyElement;
    }

    /**
     * 处理绑定value逻辑
     */
    private void handleBindValue(Element fieldElement, MethodSpec.Builder methodSpecBuilder
            , String stmtField, String valueField, boolean isBindNull, boolean isUseDefaultValue) {

        String propertyField = fieldElement.getSimpleName().toString();
        String bindType;
        boolean isBoolean = false;
        boolean isPacking = false;
        boolean isDate = false;
        boolean isPublic = fieldElement.getModifiers().contains(Modifier.PUBLIC);
        boolean isElse = false;
        boolean isModelObj = false;
        String bindValueTemplate;

        switch (fieldElement.asType().toString()) {
            case "java.lang.Boolean":
                isPacking = true;
            case "boolean":
                bindType = "bindLong";
                isBoolean = true;
                bindValueTemplate = String.format("\"1\".equals(%s.defaultValue) ? 1 : 0", propertyField);
                break;
            case "java.lang.Integer":
            case "java.lang.Long":
            case "java.lang.Short":
                isPacking = true;
            case "int":
            case "long":
            case "short":
                bindType = "bindLong";
                bindValueTemplate = String.format("Long.parseLong(%s.defaultValue)", propertyField);
                break;
            case "java.lang.Byte":
                isPacking = true;
            case "byte":
                bindType = "bindBlob";
                bindValueTemplate = String.format("Byte.parseByte(%s.defaultValue)", propertyField);
                break;
            case "java.lang.Float":
            case "java.lang.Double":
                isPacking = true;
            case "float":
            case "double":
                bindType = "bindDouble";
                bindValueTemplate = String.format("Double.parseDouble(%s.defaultValue)", propertyField);
                break;
            case "java.util.Date":
                isPacking = true;
                isDate = true;
                bindType = "bindLong";
                bindValueTemplate = String.format("Long.parseLong(%s.defaultValue)", propertyField);
                break;
            case "java.lang.String":
                isPacking = true;
                bindType = "bindText";
                bindValueTemplate = String.format("%s.defaultValue", propertyField);
                break;
            default:
                isModelObj = true;
                isPacking = true;
                bindType = "bindText";
                bindValueTemplate = String.format("%s.defaultValue", propertyField);
        }

        //属性值获取方法代码处理
        String tempPropertyField;
        if(isPublic){
            tempPropertyField = propertyField;
        }else {
            String upperFirstPropertyField = propertyField.substring(0, 1).toUpperCase() + propertyField.substring(1);
            if(isBoolean){
                if(propertyField.length() > 2 && Utils.isSpell(propertyField) && propertyField.startsWith("is")){
                    tempPropertyField = propertyField.substring(2);
                }else{
                    tempPropertyField = upperFirstPropertyField;
                }
                if(isPacking){
                    tempPropertyField = String.format("get%s",tempPropertyField);
                }else{
                    tempPropertyField = String.format("is%s",tempPropertyField);
                }
            }else{
                tempPropertyField = String.format("get%s", upperFirstPropertyField);
            }
        }

        if (isBindNull && isPacking) {
            isElse = true;

            CodeBlock.Builder codeBuilder = CodeBlock.builder()
                    .add(isPublic
                                    ? "\nif($L.$L == null){\n"
                                    : "\nif($L.$L() == null){\n"
                            , valueField, tempPropertyField);

            if (isUseDefaultValue) {
                codeBuilder.add("  if($L.defaultValue != null){\n", propertyField);
                codeBuilder.addStatement(
                        "    " + (isPublic ? "$L.$L(bindIndex++, " + bindValueTemplate + ");" : "$L.$L(bindIndex++, " + bindValueTemplate + ")")
                        , stmtField
                        , bindType
                );
                codeBuilder
                        .add("  }else{\n")
                        .add("    $L.bindNull(bindIndex++);\n  }", stmtField);
            } else {
                codeBuilder.add("   $L.bindNull(bindIndex++);", stmtField);
            }

            codeBuilder.add("  \n}else{\n");

            methodSpecBuilder.addCode(codeBuilder.build());
        }

        if (isBoolean) {
            methodSpecBuilder.addCode(
                    (isElse ? "   " : "") + (isPublic ? "$L.$L(bindIndex++, $L.$L ? 1 : 0);" : "$L.$L(bindIndex++, $L.$L() ? 1 : 0);") + (isElse ? "\n}\n" : "\n")
                    , stmtField
                    , bindType
                    , valueField
                    , tempPropertyField
            );
        } else if (isModelObj) {
            methodSpecBuilder.addCode(
                    (isElse ? "   " : "") + (isPublic ? "$L.$L(bindIndex++, toJson($L.$L));" : "$L.$L(bindIndex++, toJson($L.$L()));") + (isElse ? "\n}\n" : "\n")
                    , stmtField
                    , bindType
                    , valueField
                    , tempPropertyField
            );
        } else if(isDate){
            methodSpecBuilder.addCode(
                    (isElse ? "   " : "") + (isPublic ? "$L.$L(bindIndex++, $L.$L.getTime());" : "$L.$L(bindIndex++, $L.$L().getTime());") + (isElse ? "\n}\n" : "\n")
                    , stmtField
                    , bindType
                    , valueField
                    , tempPropertyField
            );
        } else {
            methodSpecBuilder.addCode(
                    (isElse ? "   " : "") + (isPublic ? "$L.$L(bindIndex++, $L.$L);" : "$L.$L(bindIndex++, $L.$L());") + (isElse ? "\n}\n" : "\n")
                    , stmtField
                    , bindType
                    , valueField
                    , tempPropertyField
            );
        }
    }

    /**
     * 生成实体类class
     *
     * @param builder       TypeSpecBuilder
     * @param entityElement 类节点
     */
    private void generateEntityClassAndMethod(TypeSpec.Builder builder, Element entityElement) {
        ParameterizedTypeName typeName = ParameterizedTypeName.get(
                ClassName.bestGuess(Class.class.getSimpleName())
                , TypeVariableName.get("?")
        );

        //生成字段
        FieldSpec fieldSpec = FieldSpec.builder(typeName, "entityClass")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                .initializer("$L.class", entityElement.getSimpleName())
                .build();
        builder.addField(fieldSpec);

        //生成方法
        MethodSpec methodSpec = MethodSpec.methodBuilder("getEntityClass")
                .addModifiers(Modifier.PUBLIC)
                .returns(typeName)
                .addAnnotation(Override.class)
                .addStatement("return $L", fieldSpec.name)
                .build();
        builder.addMethod(methodSpec);
    }

    /**
     * 生成获取表名属性和方法
     *
     * @param builder       TypeSpecBuilder
     * @param entityElement 类节点
     * @return 表名
     */
    private String generateTableNameFiledAndMethod(TypeSpec.Builder builder, Element entityElement) {
        Entity entity = entityElement.getAnnotation(Entity.class);
        String tableName = null;
        if (entity != null) {
            tableName = entity.tableName();
        }
        if (tableName == null || "".equals(tableName)) {
            tableName = entityElement.getSimpleName().toString();
        }

        //生成获取表的属性
        FieldSpec fieldSpec = FieldSpec.builder(String.class, "tableName")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                .initializer("$S", tableName)
                .build();
        builder.addField(fieldSpec);

        //生成获取表名的方法
        MethodSpec methodSpec = MethodSpec.methodBuilder("getTableName")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addAnnotation(Override.class)
                .addStatement("return $L", fieldSpec.name)
                .build();

        builder.addMethod(methodSpec);

        return fieldSpec.name;
    }


    /**
     * 生成获取表描述属性和方法
     *
     * @param builder       TypeSpecBuilder
     * @param entityElement 类节点
     * @return 表名
     */
    private void generateTableDescriptionFiledAndMethod(TypeSpec.Builder builder, Element entityElement) {
        //获取描述
        Description description = entityElement.getAnnotation(Description.class);
        String descriptionVal = null;
        if (description != null) {
            descriptionVal = description.value();
        }

        //若描述文本为空，则默认使用表名或者entity类名作为描述
        if (descriptionVal == null || "".equals(descriptionVal)) {
            Entity entity = entityElement.getAnnotation(Entity.class);
            if (entity != null) {
                descriptionVal = entity.tableName();
            }
            if (descriptionVal == null || "".equals(descriptionVal)) {
                descriptionVal = entityElement.getSimpleName().toString();
            }
        }

        //生成获取表的属性
        FieldSpec fieldSpec = FieldSpec.builder(String.class, "description")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                .initializer("$S", descriptionVal)
                .build();
        builder.addField(fieldSpec);

        //生成获取表名的方法
        MethodSpec methodSpec = MethodSpec.methodBuilder("getDescription")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addAnnotation(Override.class)
                .addStatement("return $L", fieldSpec.name)
                .build();

        builder.addMethod(methodSpec);
    }

    /**
     * 生成class 类属性
     *
     * @param builder            TypeSpecBuilder
     * @param tableNameFieldName 表名属性名
     * @param element            字段节点
     * @return 生成的属性是否属于主键id
     */
    private boolean generateField(TypeSpec.Builder builder, String tableNameFieldName, Element element, List<String> compositePK) {

        //是否属于主键Id
        boolean isId = element.getAnnotation(PrimaryKey.class) != null;

        //字段列信息
        String columnName = null;
        String defaultValue = null;
        ColumnInfo columnInfo = element.getAnnotation(ColumnInfo.class);
        if (columnInfo != null) {
            columnName = columnInfo.name();

            defaultValue = columnInfo.defaultValue();
            if (defaultValue == null || "".equals(defaultValue) || "[value-unspecified]".equals(defaultValue)) {
                defaultValue = null;
            }
        }

        if (columnName == null || "[field-name]".equals(columnName)) {
            columnName = element.getSimpleName().toString();
        } else {
            int index = compositePK.indexOf(columnName);
            if (index >= 0) {
                compositePK.set(index, element.getSimpleName().toString());
            }
        }

        //生成字段
        TypeMirror elementTypeMirror = element.asType();
        TypeName typeName = ClassName.bestGuess(propertyClass);
        FieldSpec.Builder fieldSpecBuilder = FieldSpec.builder(typeName, element.getSimpleName().toString());

        String doc = elementUtils.getDocComment(element);
        if(doc != null){
            fieldSpecBuilder.addJavadoc("$L",doc);
        }

        fieldSpecBuilder.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                .initializer(
                        "new $T($L,$S,$S,$T.class,$L,$L)"
                        , typeName
                        , tableNameFieldName
                        , element.getSimpleName()
                        , columnName
                        , Utils.isModelObject(elementTypeMirror) ? Object.class : elementTypeMirror
                        , isId
                        , defaultValue == null ? null : String.format("\"%s\"", defaultValue)
                );

        FieldSpec fieldSpec = fieldSpecBuilder.build();
        builder.addField(fieldSpec);

        //如果是主键id 属性 ，生成获取主键id属性的方法
        if (isId) {
            this.generateIdPropertyMethod(builder, fieldSpec);
        }

        return isId;
    }

    /**
     * 生成getIdProperty方法
     *
     * @param builder   TypeSpecBuilder
     * @param fieldSpec FieldSpec
     */
    private void generateIdPropertyMethod(TypeSpec.Builder builder, FieldSpec fieldSpec) {
        //生成方法
        MethodSpec methodSpec = MethodSpec.methodBuilder("getIdProperty")
                .addModifiers(Modifier.PUBLIC)
                .returns(ClassName.bestGuess(propertyClass))
                .addAnnotation(Override.class)
                .addStatement("return $L", fieldSpec != null ? fieldSpec.name : null)
                .build();
        builder.addMethod(methodSpec);
    }

    /**
     * 生成复合主键获取方法
     *
     * @param builder     TypeSpecBuilder
     * @param compositePK 复合主键列表
     */
    private void generateCompositePKMethod(TypeSpec.Builder builder, List<String> compositePK) {
        //处理复合主键名
        StringBuilder stringBuilder = new StringBuilder();
        for (String item : compositePK) {
            stringBuilder.append(item).append(",");
        }
        String names;
        if (stringBuilder.length() > 0) {
            names = stringBuilder.substring(0, stringBuilder.length() - 1);
        } else {
            names = stringBuilder.toString();
        }

        //生成泛型
        ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(
                ClassName.bestGuess(List.class.getName())
                , ClassName.bestGuess(propertyClass)
        );

        //生成字段
        FieldSpec.Builder fieldSpecBuilder = FieldSpec.builder(parameterizedTypeName, "compositePK")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);

        if (names == null || "".equals(names)) {
            fieldSpecBuilder.initializer("null");
        } else {
            fieldSpecBuilder.initializer("$T.asList($L)", Arrays.class, names);
        }

        FieldSpec fieldSpec = fieldSpecBuilder.build();
        builder.addField(fieldSpec);

        //生成方法
        MethodSpec methodSpec = MethodSpec.methodBuilder("getCompositePK")
                .addModifiers(Modifier.PUBLIC)
                .returns(parameterizedTypeName)
                .addAnnotation(Override.class)
                .addStatement("return $L", fieldSpec.name)
                .build();
        builder.addMethod(methodSpec);
    }

    /**
     * 生成获取属性数组方法
     *
     * @param builder    TypeSpecBuilder
     * @param properties entity内全部属性列表
     */
    private void generatePropertyArrayMethod(TypeSpec.Builder builder, List<String> properties) {
        //处理列名
        StringBuilder stringBuilder = new StringBuilder();
        for (String item : properties) {
            stringBuilder.append(item).append(",");
        }
        String names;
        if (stringBuilder.length() > 0) {
            names = stringBuilder.substring(0, stringBuilder.length() - 1);
        } else {
            names = stringBuilder.toString();
        }

        //生成泛型
        ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(
                ClassName.bestGuess(List.class.getName())
                , ClassName.bestGuess(propertyClass)
        );

        //生成字段
        FieldSpec fieldSpec = FieldSpec.builder(parameterizedTypeName, "allProperties")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                .initializer("$T.asList($L)", Arrays.class, names)
                .build();
        builder.addField(fieldSpec);

        //生成方法
        MethodSpec methodSpec = MethodSpec.methodBuilder("getAllProperties")
                .addModifiers(Modifier.PUBLIC)
                .returns(parameterizedTypeName)
                .addAnnotation(Override.class)
                .addStatement("return $L", fieldSpec.name)
                .build();
        builder.addMethod(methodSpec);

    }

    /**
     * 生成entity 实例
     *
     * @param builder       TypeSpec
     * @param entityElement 实体类节点
     */
    private void generateEntityInstanceField(TypeSpec.Builder builder, Element entityElement) {
        TypeVariableName type = TypeVariableName.get(String.format("%s_", entityElement.getSimpleName()));

        FieldSpec fieldSpec = FieldSpec.builder(type, "_instance")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                .initializer("new $L()", type.name)
                .build();
        builder.addField(fieldSpec);
    }

    /**
     * 生成实体管理类
     *
     * @param entityRelations 实体信息关联列表
     */
    private void generateEntityManager(List<EntityRelation> entityRelations) {
        String mapName = "entityMap";

        CodeBlock.Builder staticCodeBuilder = CodeBlock.builder();

        for (EntityRelation item : entityRelations) {
            staticCodeBuilder.addStatement(
                    "$L.put($T.class,$T._instance)"
                    , mapName
                    , ClassName.bestGuess(item.entityClass)
                    , ClassName.bestGuess(item.relationEntityClass)
            );
        }

        // 构建java类
        TypeSpec.Builder builder = TypeSpec.classBuilder("EntityManager")
                .addModifiers(Modifier.PUBLIC)
                .addStaticBlock(staticCodeBuilder.build());

        //生成泛型
        ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(
                ClassName.get(HashMap.class)
                , TypeVariableName.get(Class.class)
                , TypeVariableName.get("Entity")
        );

        FieldSpec fieldSpec = FieldSpec.builder(parameterizedTypeName, mapName)
                .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
                .initializer("new HashMap<Class,Entity>()")
                .build();

        //生成根据实体类全名获取表名的方法
        MethodSpec getEntityMethodSpec = MethodSpec.methodBuilder("getEntity")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                .addParameter(Class.class, "entityClass")
                .addCode(String.format("return %s.get(entityClass);", mapName))
                .addJavadoc("根据实体类全名获取表名")
                .returns(TypeVariableName.get("Entity"))
                .build();

        //生成获取全部表列表的方法
        MethodSpec getAllEntityMethodSpec = MethodSpec.methodBuilder("getAllEntity")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                .addCode(String.format("return new ArrayList(%s.values());", mapName))
                .returns(ParameterizedTypeName.get(
                        ClassName.get(ArrayList.class)
                        , TypeVariableName.get("Entity")
                ))
                .addJavadoc("获取全部表")
                .build();

        builder.addField(fieldSpec);
        builder.addMethod(getEntityMethodSpec);
        builder.addMethod(getAllEntityMethodSpec);

        this.outPutJavaFile(builder.build(), "com.richard.room.operator.api");
    }
}